<?php
/**
 * vim: et ts=4 sts=4 sw=4 fdm=marker
 *
 * 数据操作基本类	 
 *
 * @author	wang Penghai <china_php@hotmail.com>
 * @copyright 2008 5e6d Corporation.
 * @version   $Id:$
 */
if (!defined('LIB_PATH'))
{
	define('LIB_PATH' , dirname(__FILE__) . '/');
}

#include_once LIB_PATH  . 'pf_db_fields_check.class.php';
class pf_db{

	/*{{{code*/
	const DB_DRIVER_NO_EXIST = '300001';
	const DB_CONNECT_FAILT = '300002';
	const DB_GET_ALL = '300003';
	const DB_GET_ONE = '300004';
	const DB_QUERY_FAIL = '300005';
	const DB_EXEC_FAIL = '300006';
	const DB_CLOSE_FAIL = '300007';
	const DB_FIELD_FAIL = '300008';
	/*}}}*/

	/*{{{member*/
	/**
	 * 数据库连接数
	 */
	protected $__dbNum = 0;
	protected $__connectStatus = null;
	protected $__dbConf = null;
	/**
	 * 数据库配置
	 */
	protected $__c = array();
	/**
	 * 数据库对象
	 */
	protected $__db = null;
	protected $_log = null;
	/*}}}*/

	/*{{{ function */
	/*{{{ public __construct()*/
	
	/**
	 * 构造函数--
	 */
	public function __construct()
	{
		//加载日志类
		$this->_log = pf_load::lib('pf_log');
		if (false === $this->initConnect()) {
			return false;
		}
	}
	 
	/**
	 * 设置错误
	 *
	 * @see pf_log.php
	 */
	private function set_error(array $argvs)
	{
		$this->_log->set_error($argvs);
	}

	/*}}}*/
	/*{{{ public function setDbnum()*/
	
	/**
	 * 设置连接数据库
	 *
	 * @param int $num = 0 数据库连接代号,默认是0 
	 *
	 * @return void
	 */
	public function setDbnum($num=0) {
		$num = (int)$num;
		$this->__dbNum = empty($num)?0:$num;
	}

	/*}}}*/
	/*{{{ public function getDbConf()*/
	
	/**
	 * 获取数据库配置
	 *
	 * @return void
	 */
	public function getDbConf(){
		if ($this->__dbConf === null) {
			include_once DB_CONF_PATH . 'conf_db.php';		
			$this->__dbConf = (array)$DBCONF;
		}
		$this->__c = $this->__dbConf[$this->__dbNum];
	}

	/*}}}*/
	/*{{{ public function initDb()*/
	
	/**
	 * 加载数据库驱动
	 *
	 * @return void
	 */
	public function initDb()
	{
		$this->getDbConf();
		$dbdriver = isset($this->__c['dbdriver'])?$this->__c['dbdriver']:'mysql';
		$dbtype = isset($this->__c['dbtype'])?$this->__c['dbtype']:'mysql';
		
		$driverName = 'pf_' . $dbdriver;
		$driverPath = DB_DRIVER_PATH . 'driver/' . $dbtype . '/' . $driverName . '.php';
		if (!is_file($driverPath)) {
			$argvs = array(
				'code' => self::DB_DRIVER_NO_EXIST,
				'msg' => 'db driver:"' . $dbdriver . '" isnot exist!',	
			);	
			$this->set_error($argvs);
			return false;
		}	
		include_once $driverPath; 
		$this->__db = new $driverName($this->__c);
		return true;
		
	}

	/*}}}*/
	/*{{{ public function initconnect()*/
	
	/**
	 * 初始化连接
	 *
	 * @return void
	 */
	public function initConnect(){
		if (true === $this->__connectStatus[$this->__dbNum]) {
			return true;
		}	
		if (false === $this->initDb()) {
			return false;
		}
		if (false === $this->__db->__connect($this->__dbNum)) {
			$argvs = array(
					'code' => self::DB_CONNECT_FAILT,
					'msg' => 'db connect failt!',
					'dbError' => $this->__db->get_error(),
				);
			$this->set_error($argvs);
			return false;
		}
		$this->__connectStatus[$this->__dbNum] = true;
		return true;
	}

	/*}}}*/
	/*{{{ public function query()*/
	
	/**
	 * 执行查询
	 *
	 * @return array $res 成功 true | 失败 false;
	 */
	public function query($sql, $bind=array()){
			
		if (false === $this->initConnect()) {
			return false;
		}
		if (!empty($bind) && !empty($sql))
		{
			$sql = $this->bind($sql, $bind);
		}
		
		$res = $this->__db->query($sql);
		if (false === $res) {
			$argvs = array(
					'code' => self::DB_QUERY_FAIL,
					'msg' => 'query sql  fail!',
					'sql' => 'Error sql: '  . $sql,
					'dbError' => $this->__db->get_error(),
				);
			$this->set_error($argvs);
			return false;
		}
		return true;
	}

	/*}}}*/
	/*{{{ public function getALL()*/
	
	/**
	 * 获取记录集 -- 多row
	 *
	 * @return array $res 成功 记录集 | 失败 false;
	 */
	public function getAll($sql=null, $bind=array()){
			
		if (false === $this->initConnect()) {
			return false;
		}
		if (!empty($bind) && !empty($sql))
		{
			$sql = $this->bind($sql, $bind);
		}
		
		$res = $this->__db->__fetchAll($sql);
		if (false === $res) {
			$argvs = array(
					'code' => self::DB_GET_ALL,
					'msg' => 'get all res  fail!',
				);
			if (null !== $sql) {
				$argvs['sql'] = $sql;
			}
			//$argvs['dbError'] = $this->_log->get_error();
			$this->set_error($argvs);
			return false;
		}
		return $res;
	}

	/*}}}*/
	/*{{{ public function getOne()*/
	
	/**
	 * 获取记录集 -- 一条row
	 *
	 * @return array $res 成功 记录集 | 失败 false;
	 */
	public function getRow($sql=null, $bind=array()){
		if (false === $this->initConnect()) {
			return false;
		}
		if (!empty($bind) && !empty($sql))
		{
			$sql = $this->bind($sql, $bind);
		}
		$res = $this->__db->__fetch($sql);
		if (false === $res) {
			$argvs = array(
					'code' => self::DB_GET_ONE,
					'msg' => 'get res fail!',
				);
			if (null !== $sql) {
				$argvs['sql'] = $sql;
			}
			$argvs['dbError'] = $this->__db->get_error();
			$this->set_error($argvs);
			return false;
		}
		return $res;
	}

	/*}}}*/
	/*{{{ public function _exec()*/
	
	/**
	 * 执行语句-- 用于insert delete update 等不需要返回结果的语句。
	 *
	 * @return array $res 成功 记录集 | 失败 false;
	 */
	public function _exec($sql){
		if (false === $this->initConnect()) {
			return false;
		}

		$res = $this->__db->__exec($sql);
		if (false === $res) {
			$argvs = array(
					'code' => self::DB_EXEC_FAIL,
					'msg' => 'exec fail!',
				);
			if (null !== $sql) {
				$argvs['sql'] = $sql;
			}
			$argvs['dbError'] = $this->__db->get_error();
			$this->set_error($argvs);
			return false;
		}
		return $res;
	}

	public function quote($str='')
	{
		return $this->__db->__quote($str);
	}
	/*}}}*/
	/*{{{ public function closeDb()*/
	
	/**
	 * 执行语句-- 用于insert delete update 等不需要返回结果的语句。
	 *
	 * @return array $res 成功 记录集 | 失败 false;
	 */
	public function closeDb(){
		$res = $this->__db->__close();
		if (false === $res) {
			$argvs = array(
					'code' => self::DB_CLOSE_FAIL,
					'msg' => 'get res fail!',
				);
			$argvs['dbError'] = $this->__db->get_error();
			$this->set_error($argvs);
			return false;
		}
		return $res;
	}

	/*}}}*/
	/*{{{ public function tname()*/
	
	/**
	 * 给表名加前缀 
	 *
	 * @param string $tname 表名
	 *
	 * @return void 
	 */
	public function tname($tname)
	{
		$this->getDbConf();
		return $this->__c['tablepre'] . $tname;
	}

	/*}}}*/
	
	/**
	 * 创建select sql
	 * 
	 * @param string $table 表名
	 * @param  array $argv = array(
	 * 'fields'=>array('id', 'username', 'password'),
	 * 'limit' => 1,
	 * 'offset' => 0,
	 * 'order' => 'updatetime desc'
	 * 'group'=>'id'
	 * 'where'=> '1=1',
	 * )
	 */
	public function d_select($table, $argv=array(), $is_all = true)
	{
		$field = $where = $sql_limit = $order = $group = '';
		if (isset($argv['fields']) && is_array($argv['fields']) && !empty($argv['fields']))
		{
			$field = implode(',', $argv['fields']);
		} else {			
			$field = '*';
		}
		
		if (isset($argv['where']))
		{
			$where = 'WHERE ' . $argv['where'];
		}
		if (isset($argv['order']))
		{
			$order = 'ORDER BY ' . $argv['order'];
		}
		if (isset($argv['group']))
		{
			$group = 'GROUP BY ' . $argv['group'];
		}
		if (isset($argv['limit']))
		{
			$limit = (int)$argv['limit'];
			$offset = isset($argv['offset'])?(int)$argv['offset']:0;
			if ($limit !== 0)
			{
				$sql_limit = 'LIMIT ' . $offset . ' , ' . $limit;
			}
		}
		$sql = "SELECT $field FROM $table $where $order $group $sql_limit";
		if (true === $is_all)
		{
			return $this->getAll($sql);
		} else {
			return $this->getRow($sql);		
		}
	}
	
	/**
	 * 创建 update sql
	 * 
	 * @param array $argv = array(
	 * 'data'=>array('id'=>1,'username'=>'username'),
	 * 'where' => '1=1',
	 * )
	 */
	public function d_update($table, $argv=array())
	{
		if (isset($argv['data']) && !empty($argv['data']))
		{
			$data = $this->create_data($table, $argv['data']);
			if (false === $data)
			{
				return false;
			}
		} else {
			$argvs = array(
					'code' => self::DB_FIELD_FAIL,
					'msg' => 'no data!',
				);
			$this->set_error($argvs);
			return false;
		}

		if (isset($argv['where']))
		{
			$where = 'WHERE ' . $argv['where'];
		}
		$sql = "UPDATE $table SET $data $where";
		return $this->_exec($sql);
	}

	/**
	 * 
	 *
	 */
	public function d_insert($table, $value)
	{
		if (empty($value))
		{
			return false;
		}

		$data = $this->create_data($table, $value);
		if (false === $data)
		{
			return false;
		}
		$sql = "INSERT INTO $table SET $data";
		return $this->_exec($sql);
	}
	/**
	 * 检查字段合法性
	 * 
	 */
	public function create_data($table, array $data)
	{
		//$field_check = pf_db_fields_check::get_instance();
		$data_str = '';
		$error = array();

		foreach ($data as $key=>$val)
		{
			$data_str .= $key . '=\'' . $this->__db->__quote($val) . '\',';
		}
		
		$data_str = trim($data_str, ',');
		return $data_str;
	}	
	
	/**
	 * SQL 条件绑定
	 *
	 */
	protected function bind($sql, $bind)
	{
		if (!is_array($bind))
		{
			$bind = array($bind);
		}
		
		if (empty($sql) || empty($bind))
		{
			die('nothing to do!');
		}

		//搜集 ? 位置
		$pos_array = array();
		$pos = 0;
		$i = 0;
		while(true)
		{
			$pos =  strpos($sql, '?', $pos+1);
			if (false === $pos)
			{
				break;
			}
			$value = $bind[$i];
			if (!is_numeric($value))
			{
				$value = "'" . $this->quote($value) . "'";
			}
			$sql = substr_replace($sql, $value, $pos, 1);
			$i++;
		}	
		
		$bind_num = count($bind);
		if ($i != $bind_num)
		{
			die('bind wrong!');
		}	
		return $sql;
	}
	/*}}}*/
}
/**
$t= new pf_lib_db_base; 
$values = array ('data'=>array(
	'id' => '5',
	'username' => '中文',
	'date_entered' => '2008-12-30 15:24:59',
	'date_modified' => '2008-12-30 15:37:02',
	),
);
$res = $t->d_update('member', $values);
if (false === $res)
{
	$error = $t->get_error();
	var_export($error);
}
$sql = 'select * from accounts';
$res = $t->getAll($sql);
if (false === $res) {
	var_export($t->get_error());
} else { 
	var_export($res);
}
$values = array(
	'id' => '5',
	'name' => '中文',
	'date_entered' => '2008-12-30 15:24:59',
	'date_modified' => '2008-12-30 15:37:02',
);

foreach($values as $key=>$var) {
	$fields[] = $key;
	$values[] = $var;
	$v .= "'" . $var . "',";
}
$v = rtrim($v, ',');
$f = implode(',', $fields);
$sql = 'insert into accounts (' . $f . ' )values( ' . $v . ')';
$res = $t->_exec($sql);
if (false === $res) {
	var_export($t->get_error());
} else {
	var_export($res);
}

$t->closeDb();
*/
